package com.szeldon.pj.jps.exp;

import com.szeldon.pj.jps.data.store.SBAStore;
import com.szeldon.pj.jps.datastore.SimpleObject;
import com.szeldon.pj.jps.envs.ENVS;
import com.szeldon.pj.jps.qres.AbstractQueryResult;
import com.szeldon.pj.jps.qres.BagResult;
import com.szeldon.pj.jps.qres.BooleanResult;
import com.szeldon.pj.jps.qres.QResStack;
import com.szeldon.pj.jps.visitor.ASTVisitor;

public class BiggerBinaryExpression extends BinaryExpression {

	/**
	 * 
	 * @param leftExpression
	 * @param rightExpression
	 */
	public BiggerBinaryExpression(Expression leftExpression, Expression rightExpression) {
		super(leftExpression, rightExpression);
	}

	public void accept(ASTVisitor astVisitor, ENVS envs, QResStack qResStack, SBAStore store) {

		if (!isSupportedExpressionType(leftExpression) || !isSupportedExpressionType(rightExpression)) {
			throw new IllegalStateException("Both subexpressions for BiggerBinaryExpression must be of "
					+ "Name or Terminal type. Currently left is " + leftExpression.getClass().getName()
					+ " and right is " + rightExpression.getClass().getName() + ".");
		}

		AbstractQueryResult leftResult = tryToMakeResultFromExpression(leftExpression, envs);
		AbstractQueryResult rightResult = tryToMakeResultFromExpression(rightExpression, envs);

		if (leftResult == null && rightResult == null) {
			qResStack.push(new BooleanResult(ASTVisitor.compareExpressions(store, (TerminalExpression) leftExpression,
					(TerminalExpression) rightExpression) == 1));
		} else if (leftResult != null) {
			qResStack.push(new BooleanResult(ASTVisitor.compareAbstractQueryResultWithExpression(store,
					leftResult, (TerminalExpression) rightExpression) == 1));
		} else if (rightResult != null) {
			qResStack.push(new BooleanResult(ASTVisitor.compareAbstractQueryResultWithExpression(store,
					rightResult, (TerminalExpression) leftExpression) == -1));
		} else {
			qResStack.push(new BooleanResult(ASTVisitor.compareResults(store, leftResult, rightResult) == 1));
		}

	}

	/**
	 * True if given expression is supported by this expression.
	 * 
	 * @param expression
	 * @return
	 */
	private boolean isSupportedExpressionType(Expression expression) {
		if (expression instanceof TerminalExpression || expression instanceof NameExpression) {
			return true;
		} else {
			return false;
		}
	}

	private AbstractQueryResult tryToMakeResultFromExpression(Expression expression, ENVS envs) {
		AbstractQueryResult result = null;
		if (expression instanceof NameExpression) {
			BagResult leftResultBag = envs.bind(((NameExpression) expression).getName());
			result = leftResultBag.getElements().iterator().next();
		} else if (expression instanceof TerminalExpression) {
			// nothing to do
		}

		return result;
	}

	@Override
	public int compareTo(SimpleObject object) throws IllegalStateException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public String getValueAsString() {
		return ">";
	}
}
